﻿using Engine;
using GameEntitySystem;
using System;
using System.Collections.Generic;

namespace CommandBlock
{
    /// <summary>
    /// 命令方块电路元素
    /// </summary>
    public class CommandElectricElement : ElectricElement
    {
        public SubsystemCommand m_subsystemCommand;

        public CommandData m_commandData;

        public float m_voltage;

        public bool clockAllowed = true;

        public SubmitResult m_submitResult;

        public CommandElectricElement(SubsystemElectricity subsystemElectricity, Point3 position)
            : base(subsystemElectricity, new List<CellFace>
            {
                    new CellFace(position.X, position.Y, position.Z, 0),
                    new CellFace(position.X, position.Y, position.Z, 1),
                    new CellFace(position.X, position.Y, position.Z, 2),
                    new CellFace(position.X, position.Y, position.Z, 3),
                    new CellFace(position.X, position.Y, position.Z, 4),
                    new CellFace(position.X, position.Y, position.Z, 5)
            })
        {
            m_commandData = subsystemElectricity.Project.FindSubsystem<SubsystemCommandBlockBehavior>(true).GetCommandData(position);
            m_subsystemCommand = subsystemElectricity.Project.FindSubsystem<SubsystemCommand>(true);
            m_submitResult = SubmitResult.Fail;
        }

        public override float GetOutputVoltage(int face)
        {
            return m_voltage;
        }

        public override bool Simulate()
        {
            try
            {
                if (m_commandData == null) return false;
                if (m_commandData.Mode == WorkingMode.Default)
                {
                    if (base.CalculateHighInputsCount() > 0)
                    {
                        m_submitResult = m_subsystemCommand.Submit(m_commandData.Name, m_commandData, false);
                        m_subsystemCommand.ShowSubmitTips(string.Empty, true, m_submitResult, m_commandData);
                        return m_submitResult == SubmitResult.Success;
                    }
                }
                else if (m_commandData.Mode == WorkingMode.Condition)
                {
                    base.SubsystemElectricity.QueueElectricElementForSimulation(this, base.SubsystemElectricity.CircuitStep + 1);
                    if (m_submitResult != SubmitResult.Success && m_submitResult != SubmitResult.Fail)
                    {
                        return false;
                    }
                    m_submitResult = m_subsystemCommand.Submit(m_commandData.Name, m_commandData, true);
                    if (m_submitResult != SubmitResult.OutRange && m_submitResult != SubmitResult.Invalid)
                    {
                        m_subsystemCommand.ShowSubmitTips(string.Empty, true, m_submitResult, m_commandData);
                    }
                    m_voltage = (m_submitResult == SubmitResult.Success) ? 1f : 0f;
                    return true;
                }
                else if (m_commandData.Mode == WorkingMode.Variable)
                {
                    m_voltage = 0f;
                    int[] signals = GetSignals();
                    int clockSignal = signals[4];
                    if (IsVariableSyncMode())
                    {
                        if (clockSignal >= 8 && clockAllowed)
                        {
                            clockAllowed = false;
                            return VariableSubmit(signals);
                        }
                        if (clockSignal < 8) clockAllowed = true;
                    }
                    else
                    {
                        if (signals[0] > 0 || signals[1] > 0 || signals[2] > 0 || signals[3] > 0)
                        {
                            return VariableSubmit(signals);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Warning("CommandElectricElement:" + e.Message);
            }
            return false;
        }

        public bool VariableSubmit(int[] signals)
        {
            m_commandData = DataHandle.SetVariableData(m_commandData, signals);
            m_submitResult = m_subsystemCommand.Submit(m_commandData.Name, m_commandData, false);
            m_subsystemCommand.ShowSubmitTips(string.Empty, true, m_submitResult, m_commandData);
            if (m_submitResult == SubmitResult.Success)
            {
                m_voltage = 1f;
                return true;
            }
            else
            {
                m_voltage = 0f;
                return false;
            }
        }

        public int[] GetSignals()
        {
            int[] signals = new int[6];
            foreach (ElectricConnection connection in base.Connections)
            {
                if (connection.ConnectorType != ElectricConnectorType.Output && connection.NeighborConnectorType != 0)
                {
                    switch (connection.NeighborConnectorFace)
                    {
                        case 0: signals[0] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(0) * 15f); break;
                        case 1: signals[1] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(1) * 15f); break;
                        case 2: signals[2] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(2) * 15f); break;
                        case 3: signals[3] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(3) * 15f); break;
                        case 4: signals[4] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(4) * 15f); break;
                        case 5: signals[5] = (int)MathUtils.Round(connection.NeighborElectricElement.GetOutputVoltage(5) * 15f); break;
                        default: break;
                    }
                }
            }
            return signals;
        }

        public bool IsVariableSyncMode()
        {
            bool clockConnection = false;
            foreach (ElectricConnection connection in base.Connections)
            {
                if (connection.ConnectorType != ElectricConnectorType.Output && connection.NeighborConnectorType != 0)
                {
                    ElectricConnectorDirection? connectorDirection = SubsystemElectricity.GetConnectorDirection(base.CellFaces[0].Face, 0, connection.ConnectorFace);
                    if (connectorDirection.HasValue)
                    {
                        if (connectorDirection == ElectricConnectorDirection.Bottom) clockConnection = true;
                    }
                }
            }
            return clockConnection;
        }
    }
}